package com.ants.project.core.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * Aspectj切入点语法定义
 * 整个表达式可以分为五个部分：
 * 1、execution(): 表达式主体。
 * 2、第一个*号：表示返回类型，*号表示所有的类型。
 * 3、包名：表示需要拦截的包名，后面的两个句点表示当前包和当前包的所有子包，com.sample.service.impl包、子孙包下所有类的方法。
 * 4、第二个*号：表示类名，*号表示所有的类。
 * 5、*(..):最后这个星号表示方法名，*号表示所有的方法，后面括弧里面表示方法的参数，两个句点表示任何参数。
 *
 * 应用场景
 * Authentication 权限
 * Caching 缓存
 * Context passing 内容传递
 * Error handling 错误处理
 * Lazy loading 懒加载
 * Debugging 调试
 * logging, tracing, profiling and monitoring 记录跟踪 优化 校准
 * Performance optimization 性能优化
 * Persistence 持久化
 * Resource pooling 资源池
 * Synchronization 同步
 * Transactions 事务
 * Created by liushun on 2016/7/9.
 */
@Aspect
@Service
public class MyAopInterceptor {

   // @Pointcut("execution(public * com.ants.project.fast.app.v1.service..*.mySleep*(..))")
    @Pointcut("execution(* com.ants.project.fast.app.controller.DynamicCallController.test(..))")
    public void abc(){
        System.out.println("### 定义切面");
    }


    /**
     * 环绕通知需要携带ProceedingJoinPoint 这个类型的参数
     * 环绕通知类似于动态代理的全过程 ProceedingJoinPoint类型的参数可以决定是否执行目标函数
     * 环绕通知必须有返回值
     * @param proceedingJoinPoint
     * @return
     */
    @Around("abc()")
    public Object testE(ProceedingJoinPoint proceedingJoinPoint){
        Object result=null;
        Object classMethod=proceedingJoinPoint.getSignature();
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String rightnow=sdf.format(date);
        try {
            //前置通知
            System.out.println(rightnow+"环绕通知执行了【"+classMethod+"方法开始执行......】 Before");
            //执行目标方法
            result = proceedingJoinPoint.proceed();
            //返回通知
            System.out.println(rightnow+"环绕通知正常执行【"+classMethod+"方法完毕......】"+" After【返回结果：】");
        } catch (Throwable e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            //异常通知
            System.out.println(rightnow+"环绕通知非正常执行【"+classMethod+"方法完毕，抛出异常......】"+"AfterThrowing 【返回异常：】"+e);
        }
            //后置通知
        System.out.println(rightnow+"环绕通知执行【"+classMethod+"方法完毕】 - AfterReturning"+result);
        Object[] args = proceedingJoinPoint.getArgs();
        if(Arrays.binarySearch(args, "callback")>-1)
            return "jsonCallBack("+result+");";
        else
            return result;
    }

    /**
     * 切面的前置方法 即方法执行前拦截到的方法 记录并输出
     * 在目标方法执行之前的通知
     * @param joinPoint
     */
    @Before("abc()")
    public void testA(JoinPoint joinPoint){
        System.out.println("======================方法开始======================");
        Object object = joinPoint.getSignature();
        String methodName = joinPoint.getSignature().getName();
        List<Object> list = Arrays.asList(joinPoint.getArgs());
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String rightnow=sdf.format(date);
        System.out.println(rightnow+"执行了【"+object+"方法开始执行......】");
        System.out.println("******参数"+list+"******");
    }

    /**
     * 在方法正常执行通过之后执行的通知叫做返回通知
     * 可以返回到方法的返回值 在注解后加入returning
     * @param joinPoint
     */
    @AfterReturning(pointcut="abc()", returning="result")
    public void testC(JoinPoint joinPoint, String result){
        Object object = joinPoint.getSignature();
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String rightnow=sdf.format(date);
        System.out.println(rightnow+"执行了【"+object+"方法正常执行结束......】"+"【返回结果:"+result+"】");
        System.out.println("√√√√√√√√√√√√√√√√√√√√√√方法结束√√√√√√√√√√√√√√√√√√√√√√");
    }

    /**
     * 切面的后置方法，不管抛不抛异常都会走此方法
     * 在目标方法执行之后的通知
     * @param joinPoint
     */
    @After("abc()")
    public void testB(JoinPoint joinPoint){
        Object object = joinPoint.getSignature();
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String rightnow=sdf.format(date);
        System.out.println(rightnow+"执行了【"+object+"方法结束......】");
    }

    /**
     * 在目标方法非正常执行完成 发生异常 抛出异常的时候会走此方法
     * 获得异常可以用throwing
     * @param joinPoint
     * @param e
     */
    @AfterThrowing(pointcut="abc()", throwing="e")
    public void testD(JoinPoint joinPoint, Exception e){
        Object object = joinPoint.getSignature();
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String rightnow=sdf.format(date);
        System.out.println(rightnow+"执行了【"+object+"方法发生异常......】"+"【异常报告:"+e+"】");
        System.out.println("xxxxxxxxxxxxxxxxxx方法发生异常结束xxxxxxxxxxxxxxxxxx");
    }

}
